package com.kuangstudy.service.hotproduct;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kuangstudy.constant.RedisConstants;
import com.kuangstudy.entity.Product;
import com.kuangstudy.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author panghu
 * @version 1.0.0
 * @createTime 2023年09月19日 19:50:00
 * @Description
 */
@Service
@Slf4j
public class HotProductListService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    // 做定时任务分页使用
    private final AtomicInteger atomicInteger = new AtomicInteger(1);

    @PostConstruct
    private void initData() {
        List<Product> productList = new ArrayList<>();
        if (!redisTemplate.hasKey(RedisConstants.HOT_PRODUCT_LIST_MASTER)) {
            log.info("启动加载【50件特价商品】到redis的【master】list中...");
            productList = this.loadHotProductInfo();
            this.redisTemplate.opsForList().leftPushAll(RedisConstants.HOT_PRODUCT_LIST_MASTER, productList);
        }
        if (!redisTemplate.hasKey(RedisConstants.HOT_PRODUCT_LIST_SLAVE)) {
            log.info("启动加载【50件特价商品】到redis的【slave】list中...");
            this.redisTemplate.opsForList().leftPushAll(RedisConstants.HOT_PRODUCT_LIST_SLAVE, productList);
        }
    }

    /**
     * 分页查新数据库的热点商品的数据
     *
     * @return
     */
    public List<Product> loadHotProductInfo() {
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        Page<Product> page = new Page<>(atomicInteger.get(), 50);
        Page<Product> selectPage = productMapper.selectPage(page, queryWrapper);
        List<Product> productList = selectPage.getRecords();
        atomicInteger.incrementAndGet();
        return productList;
    }


    /**
     * 定时任务: 加载热点商品到redis中
     * 每隔5min执行一次
     * 用master-slave节点解决缓存击穿的问题
     */
    @Scheduled(cron = "0 0/5 * * * ? ")
    public void taskHotProduct() {
        try {
            log.info("定时刷新特价商品....");
            // 从数据库中查询出特价商品
            List<Product> productList = this.loadHotProductInfo();
            if (!CollectionUtils.isEmpty(productList)) {
                // todo 注意：为了解决缓存击穿的问题，这里先写入slave，再写入master；假设master没有击穿，直接读取的到；假设master被击穿了，他不会冲到数据库，先会去slave去查询，而这个时候slave节点是在master节点之前放的，此时master节点是最新的【如果调换顺序先master再slave也可以解决击穿问题，但是查出来slave是旧的的数据】
                // todo 【注意：这里的主从只是数据结构上的主备，不是集群上的主从要注意！！！】
                // 删除slave原来的特价商品
                this.redisTemplate.delete(RedisConstants.HOT_PRODUCT_LIST_SLAVE);
                // 把特价商品添加到slave集合中
                this.redisTemplate.opsForList().leftPushAll(RedisConstants.HOT_PRODUCT_LIST_SLAVE, productList);

                // 删除master原来的特价商品 todo 有击穿问题
                this.redisTemplate.delete(RedisConstants.HOT_PRODUCT_LIST_MASTER);
                // 把特价商品添加到master集合中
                this.redisTemplate.opsForList().leftPushAll(RedisConstants.HOT_PRODUCT_LIST_MASTER, productList);
            }else {
                log.info("数据库热门商品已经全部加载完成");
            }
        } catch (Exception ex) {
            throw new RuntimeException("服务器忙碌中...");
        }
    }

}
